/** Class Name: OORLeadRoundRobinQueue 
 * Author: Accenture
 * Requirement/Project Name: OOR
 * Requirement Description: Class will be called by a triiger on insert whenever Market group creates Leads in Bulk(Data Loader)
 */

public class OORLeadRoundRobinQueue
{
    class userInfoClass
    {
        List<Assignment_Groups__c> lag;
        Integer idx;
    }
        
    public static void executeRoundRobin(List<Lead> leadsList,Map <ID, Lead> queryRequestMap)
    {
    
        Set<Id> sGroupIds = new Set<Id>();
        Set<Id> queueIds = new Set<Id>();
        Set<Id> LeadIds= new Set<Id>();

        List<Assignment_Groups__c> lagroup = new List<Assignment_Groups__c>();
        List<Lead> updateqrList = new List<Lead>();
        List<Lead> qrList = null; 
        List<Assignment_Groups__c> lAG = null;                                                                         
        List<Assignment_Group_Name__c> assignmentGroup = null;                                                               
        
        // Stores the Assignment_Group_Name__c into the map assignmentGroupMap  
        Map<ID, Assignment_Group_Name__c> assignmentGroupMap  = new Map<ID, Assignment_Group_Name__c> ();
        Map<Id, userInfoClass> mGroupMember = new Map<Id, userInfoClass>();
        // Stores the Assignment_Groups__c into the map mUpdateAG 
        Map<Id, Assignment_Groups__c> mUpdateAG = new Map<Id, Assignment_Groups__c>();
       // Maps the queue ID with Assignment group
        Map<ID, ID> mAGQIdbyQueueId = getmAGQIdbyQueueId();
        for(Lead  c : leadsList)
        {   
            
                // See if the owner (i.e. queue) is linked to an assignment group
                system.debug('INSIDE UPDATE');  
                if(mAGQIdbyQueueId.containsKey(c.OwnerId))
                {
                    Id gId = mAGQIdbyQueueId.get(c.OwnerId);
                    sGroupIds.add(gId);
                    queueIds.add(c.OwnerId);
                    LeadIds.add(c.Id);
                }
            
        }

        if(!LeadIds.isEmpty())
        {
            qrList = getOwnerIDOfLeads(LeadIds);
            lAG = getAssignmentGroupsMembers(sGroupIds);                                                                         
            assignmentGroup = getAssignmentGroup(sGroupIds);                                                               
           
            for(Assignment_Group_Name__c obj : assignmentGroup )
            {    
               assignmentGroupMap.put(obj.id, obj ) ;
            }                                                                 
            for(Id gId : sGroupIds)
            {
                for(Assignment_Groups__c ag : lAG)
                {
                    if(ag.Group_Name__c == gId)
                    {
                        lagroup.add(ag);
                    }  
                }
                if(!lagroup.isEmpty())
                {   
                    userInfoClass u = new userInfoClass();
                    u.lag = lagroup;
                    u.idx = 0;
                    for(ID qId : queueIds)
                    {   
                        if(mAGQIdbyQueueId.get(qId) == gId)
                        {   
                            mGroupMember.put(qId, u);
                        }
                    }
                }
            }
        
            for(Lead c : qrList)
            {

                if(mGroupMember.containsKey(c.OwnerId))
                {
                    userInfoClass u_item = mGroupMember.get(c.OwnerId);
                    Assignment_Groups__c ag_item = u_item.lag[u_item.idx];
                    Assignment_Group_Name__c assignGroupObj  = assignmentGroupMap.get(ag_item.Group_Name__c);
            
                    //Check the assignment group is part of round robin
                    if(assignGroupObj!= null && assignGroupObj.Round_Robin__c)
                    {
                        c.OwnerId = ag_item.User__c;
                        updateqrList.add(c); // add into case update list
                    }
                    //Check if  assignment goroup is associated with the queue and is  part of round robin
                    if(!mUpdateAG.containsKey(ag_item.Id) && assignGroupObj!= null && assignGroupObj.Round_Robin__c)
                    {
                        datetime now = datetime.now();
                        ag_item.Last_Assignment__c = now;
                        ag_item.Millisecond__c = now.millisecondGMT();
                        mUpdateAG.put(ag_item.Id, ag_item);
                    }
                    u_item.idx++;
                    u_item.idx = math.mod(u_item.idx, u_item.lag.size());
                }
            }
       
            try 
            {
                if(updateqrList.size() > 0)
                {
                    update updateqrList; // OwnerId must be updated again after insert/update
                }
                if(mUpdateAG.values().size() >0)
                {
                    update mUpdateAG.values(); // update Assignment Time for Assignment Group Member
                }   
            }
            catch (Exception ex)
            {
                GeneralConstants.mailAnyExceptionToMe('OORLeadRoundRobinQueue','executeRoundRobin',ex);
                System.debug('Exception in update the Lead and Assignment Group Member: ' + ex);
            }
        }
    }
    /*
     *  Returns the Lead
     *
     **/
    public static List<Lead> getOwnerIDOfLeads( Set<Id> LeadIds)
    {
        return [select Id, OwnerId from     Lead where Id IN: LeadIds];   
    }
    /*
     *  Returns the users of the Assignment group
     *
     **/
    public static List<Assignment_Groups__c> getAssignmentGroupsMembers( Set<Id> sGroupIds)
    {
        
        return [select a.Id, a.Name, a.Group_Name__c, a.User__c from Assignment_Groups__c a
                                                                         where  a.Active__c =: 'true' 
                                                                         and a.User_Active__c =: 'true' 
                                                                     //    and a.Round_Robin__c = true 
                                                                         and a.Group_Name__c IN: sGroupIds                                                                         
                                                                         ORDER BY Last_Assignment__c, Millisecond__c];
    } 
     /*
     *  Returns  the Assignment group
     *
     **/  
    public static List<Assignment_Group_Name__c> getAssignmentGroup(Set<Id> sGroupIds)
    {
       return [Select Id ,a.Name, a.OwnerId, a.Round_Robin__c from Assignment_Group_Name__c a where id in :sGroupIds];                                                                  
    }
    
    /*
     *  Returns  queue associated the Assignment group
     *
     **/  
    
    public static Map<ID, ID> getmAGQIdbyQueueId(){
    
        Map<ID, ID> mAGQIdbyQueueId = null;
        if(mAGQIdbyQueueId == null){
            mAGQIdbyQueueId = new Map<ID, ID>();
            for(Assignment_Group_Queues__c g : [select a.Assignment_Group_Name__c, a.Id, a.Name, a.QueueId__c  
                                                from Assignment_Group_Queues__c a 
                                                where a.Valid_Queue__c  =: true and a.Active__c =: 'true' and Assignment_Group_Name__r.Type__c = 'Lead' ]){
                mAGQIdbyQueueId.put(g.QueueId__c, g.Assignment_Group_Name__c);      
            }
        }      
        return mAGQIdbyQueueId;
    } 
    @future
      public static void ASmember_insert(Set<Id> userid){
          list<Assignment_Groups__c> Groupmembers= new list<Assignment_Groups__c>();
          Map<String,Assignment_Group_Name__c> Groupname= new Map<String,Assignment_Group_Name__c>();
          List<User> UserNew = new List<User>();
          Set<String> OfficeCodes = new Set<String>();
          Set<Id> UserIdSet = new Set<Id>();
          for(User user:[Select id,OOR_Hire_Date__c,SFA_Office__c from User where Id IN:userid]){
              if(user.SFA_Office__c != NULL && user.OOR_Hire_Date__c != NULL){
                 UserNew.add(user);
                 OfficeCodes.add(user.SFA_Office__c);
               }
           } 
           for(Assignment_Group_Name__c AssGroup:[select id,Name from Assignment_Group_Name__c where Type__c = 'Lead']){
               Groupname.put(AssGroup.Name,AssGroup);
           }
           for(User user:UserNew){
               Assignment_Groups__c Groupmember= new Assignment_Groups__c();
               Groupmember.User__c = user.Id;
                   for(String Str:Groupname.keySet()){
                       if(Str.Contains(user.SFA_Office__c)){
                           Groupmember.Group_Name__c = Groupname.get(Str).Id;
                           break;
                       }
                   }
               if(Groupmember.Group_Name__c != NULL){    
                   Groupmembers.add(Groupmember);
               }
       
           }
           if(Groupmembers.size()>0){
                   try{
                       Insert Groupmembers;
                   }
                   Catch(DMLException e){
                       system.debug('DMLException456'+e);
                   }
           }
      }
  /*  static testMethod void testOORLeadRoundRobinQueue(){
      
        Profile p = [select id from profile where name='SFA OOR Media Consultants'];
        User u2 = new User(alias = 'Opt2', email='sysadminOpty2@accenture.com',emailencodingkey='UTF-8', lastname='Test Opty 2', languagelocalekey='en_US',localesidkey='en_US', profileid = p.Id,timezonesidkey='Asia/Calcutta', username='testOppty2@testorg.com',SFA_Office__c='BLT',IsActive = True,OOR_Hire_Date__c= Date.Today());              
        
           
        Assignment_Group_Name__c ASGName = new Assignment_Group_Name__c();
        ASGName.Name = 'OOR Leads Reassignment - [BLT]' ;
        ASGName.Type__c = 'Lead';
        ASGName.Office_Code__c = 'BLT';
        ASGName.Round_Robin__c = True;
        insert ASGName;
        
        Insert u2; 
        system.debug('&&&&&&&' + u2+ASGName);  
        
        Set<ID> Us1 = new Set<ID>();
        Us1.add(u2.id);      
        OORLeadRoundRobinQueue.ASmember_insert(Us1);
        
        Group grp = new Group(Name='Sharkpool - Baltimore[BLT]',Type='Queue');
        insert grp;

        QueueSobject mappingObject = new QueueSobject(QueueId = grp.Id, SobjectType = 'Lead');
        System.runAs(new User(Id = UserInfo.getUserId()))
        {insert mappingObject;}
        
        Profile q = [select id from profile where name='SFA OOR Markets Group'];
        User u3 = new User(alias = 'Opt21', email='sysadminOpty21@accenture.com',emailencodingkey='UTF-8', lastname='Test Opty 21', languagelocalekey='en_US',localesidkey='en_US', profileid = q.Id,timezonesidkey='Asia/Calcutta', username='testOppty21@testorg.com',SFA_Office__c='BLT',IsActive = True,OOR_Hire_Date__c= Date.Today());              
        insert u3;
        
        Assignment_Groups__c ASG = new Assignment_Groups__c();
        ASG.Group_Name__c = ASGName.ID;
        ASG.Active__c = 'True';
        ASG.User__c = u2.id;        
        insert ASG;
        
        Assignment_Group_Queues__c AGQ = new Assignment_Group_Queues__c();
        AGQ.Name = 'OOR Leads Reassignment - [BLT]';
        AGQ.QueueId__c = grp.Id;
        AGQ.Assignment_Group_Name__c = ASGName.ID;
        AGQ.Active__c = 'True';
        AGQ.Valid_Queue__c = True;
        insert AGQ;     
                     
        ID LocalAdsLeadRecordType = RecordTypeHelper.GetRecordTypeID('Lead', 'Local Advertiser');
        Lead L1 = new Lead();
        L1.LastName = 'TestLead1#';
        L1.Company = 'Accenture TestLead 1';
        L1.Phone = ' 8596596665';
        L1.Status = 'New';
        L1.Lead_Status_ReadOnly__c = 'New'; 
        L1.ownerid = grp.id;
        L1.FirstName = 'Test#Lead';
        L1.RecordTypeID = LocalAdsLeadRecordType;        
        insert L1;
     
    
        
        Set<ID> QueId = New Set<ID>();
        Set<ID> GQueId = New Set<ID>();
        Set<ID> LeadId = New Set<ID>();
        list<Lead> LeadList = new List<Lead>();
        Map<Id, Lead> MapLead = New Map<Id, Lead>();
        
        GQueID.add(ASG.Id);
        QueID.add(ASGName.ID);
        LeadId.add(L1.Id);
        LeadList = [Select OwnerId from Lead where LastName = 'TestLead1#'];
        MapLead.put(L1.Ownerid, L1);
        OORLeadRoundRobinQueue.getmAGQIdbyQueueId();
        OORLeadRoundRobinQueue.executeRoundRobin(LeadList,MapLead);
        OORLeadRoundRobinQueue.getOwnerIDOfLeads(LeadId);
        OORLeadRoundRobinQueue.getAssignmentGroupsMembers(GQueId);
        OORLeadRoundRobinQueue.getAssignmentGroup(QueID);       
}*/
}